package com.chenjt.juc.eight_CAS;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 注释：
 * 题目：实现一个自旋锁，复习CAS思想
 * 自旋锁的好处：循环比较获取没有类似wait的阻塞
 *
 * 通过CAS操作完成自旋锁，A线程先进来调用myLock方法自己持有锁5秒钟，B随后进来后发现
 * 当前有线程持有锁，所以只能通过自旋锁等待，直到A释放锁后B随后抢到
 *
 * @author chenjt
 * @date 2024/7/11 10:26
 */
public class SpinLockDemo {


    AtomicReference<Thread> atomicReference = new AtomicReference<Thread>();


    public void lock(){
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"\t" + "---- come in");
        // 第一次上锁时是true，不进入循环，上锁之后其他线程进来获取锁，是false，取反，为true，进入循环等待锁释放，
        // 使用时希望atomicReference里面没有内容，就把内容置为当前线程，模拟抢到锁的情况
        while(!atomicReference.compareAndSet(null,thread)){

        }
    }


    public void unLock(){
        Thread thread = Thread.currentThread();
        // 使用时希望atomicReference里面存的是当前线程，然后把内容置为null，模拟释放锁的情况
        atomicReference.compareAndSet(thread,null);
        System.out.println(Thread.currentThread().getName()+"\t"+"---- task over,unLock...");

    }


    public static void main(String[] args) {

        SpinLockDemo spinLockDemo = new SpinLockDemo();

        new Thread(()->{
            spinLockDemo.lock();
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            spinLockDemo.unLock();
        },"A").start();

        // 暂停一下，保证A线程先启动
        try {
            TimeUnit.MILLISECONDS.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            /**
             * 锁被A线程拿走了，要等待5秒才能释放，所以这里一直卡在while循环体里面
             * 5秒后A线程释放锁，B线程能拿到锁了，跳出while循环
             */
            spinLockDemo.lock();
            spinLockDemo.unLock();

        },"B").start();

    }


}
